#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+5;
typedef int LL;
typedef pair<LL,LL>P;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
vector<LL>e[maxn];
struct Tree{
    LL l,r,val;
}tree[maxn<<2];
inline void push_up(LL p){
    tree[p].val=max(tree[p<<1].val,tree[p<<1|1].val);
}
inline void build(LL p,LL l,LL r)
{
    tree[p].l=l;tree[p].r=r;tree[p].val=0;
    if(l==r) {return;}
    LL mid=(l+r)>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    push_up(p);
}
inline void modify(LL p,LL l,LL r,LL d){
    if(l<=tree[p].l&&r>=tree[p].r)
    {
        tree[p].val=max(tree[p].val,d);
        return;
    }
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(l<=mid)  modify(p<<1,l,r,d);
    if(r>mid) modify(p<<1|1,l,r,d);
    push_up(p);
}
inline LL query(LL p,LL l,LL r)
{
    if(l<=tree[p].l&&r>=tree[p].r)
    {
        return tree[p].val;
    }
    LL mid=(tree[p].l+tree[p].r)>>1;
    LL ans=0;
    if(l<=mid) ans=max(ans,query(p<<1,l,r));
    if(r>mid) ans=max(ans,query(p<<1|1,l,r));
    return ans;
}
int main(void){
   	cin.tie(0);std::ios::sync_with_stdio(false);
    LL n,m;cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        LL x,y;cin>>x>>y;
        e[x].push_back(y);
    }
    build(1,1,n);
    for(int i=1;i<=n;i++) sort(e[i].begin(),e[i].end());
    LL ans=0;
    for(int i=1;i<=n;i++)
    {
        vector<P>tmp;
        for(int j=0;j<e[i].size();j++)
        {
            LL res=query(1,1,e[i][j]-1);
            ans=max(ans,res+1);
            tmp.push_back({res+1,e[i][j]});
        }
        for(int j=0;j<tmp.size();j++)
        {
            modify(1,tmp[j].second,tmp[j].second,tmp[j].first);
        }
    }
    cout<<ans<<"\n";
   	return 0;
}
